package com.tlgen.doc.utils;

import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.tlgen.doc.utils.FileUtils.getAllFile;

public class ScanUtils {

    /**
     * 获取包含请求方法的全部接口类
     *
     * @return
     */
    public static List<String> getControllerClasses() {
        List<String> classes = ScanUtils.getClassesWithAnnotation(RequestMapping.class);
        List<String> GetMapping = ScanUtils.getClassesMethodWithAnnotation(org.springframework.web.bind.annotation.GetMapping.class);
        List<String> PostMapping = ScanUtils.getClassesMethodWithAnnotation(org.springframework.web.bind.annotation.PostMapping.class);
        List<String> PutMapping = ScanUtils.getClassesMethodWithAnnotation(org.springframework.web.bind.annotation.PutMapping.class);
        List<String> DeleteMapping = ScanUtils.getClassesMethodWithAnnotation(org.springframework.web.bind.annotation.DeleteMapping.class);
        classes.addAll(GetMapping);
        classes.addAll(PostMapping);
        classes.addAll(PutMapping);
        classes.addAll(DeleteMapping);
        classes = classes.stream().distinct().collect(Collectors.toList());
        return classes;
    }


    /**
     * 获取根目录下包含指定注解下的类
     *
     * @param annotationType
     * @return
     */
    public static List<String> getClassesWithAnnotation(Class<? extends Annotation> annotationType) {
        List<String> classNames = new ArrayList<>();
        String localDirectory = System.getProperty("user.dir") + "\\";
        File filePath = new File(localDirectory);
        List<File> aFiles = new ArrayList<>();
        getAllFile(filePath, aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        try {
            for (File aFile : aFiles) {
                String absolutePath = aFile.getAbsolutePath();
                String className = absolutePath
                        .substring(absolutePath.indexOf("\\java") + 6, absolutePath.lastIndexOf(".java"))
                        .replaceAll("\\\\", ".");
                Class<?> clazz = Class.forName(className);
                Annotation[] annotations = clazz.getAnnotationsByType(annotationType);
                if (annotations.length > 0) {
                    classNames.add(clazz.getName());
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return classNames;
    }

    /**
     * 获取根目录下方法上包含指定注解下的类
     *
     * @param annotationType
     * @return
     */
    public static List<String> getClassesMethodWithAnnotation(Class<? extends Annotation> annotationType) {
        List<String> classNames = new ArrayList<>();
        String localDirectory = System.getProperty("user.dir");
        File filePath = new File(localDirectory);
        List<File> aFiles = new ArrayList<>();
        getAllFile(filePath, aFiles);
        aFiles = aFiles.stream().filter(x -> x.getName().contains(".java")).collect(Collectors.toList());
        try {
            for (File aFile : aFiles) {
                String absolutePath = aFile.getAbsolutePath();
                String className = absolutePath
                        .substring(absolutePath.indexOf("\\java") + 6, absolutePath.lastIndexOf(".java"))
                        .replaceAll("\\\\", ".");
                Class<?> clazz = Class.forName(className);
                for (Method declaredMethod : clazz.getDeclaredMethods()) {
                    Annotation annotation = declaredMethod.getAnnotation(annotationType);
                    if (Objects.nonNull(annotation)) {
                        classNames.add(clazz.getName());
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        classNames = classNames.stream().distinct().collect(Collectors.toList());
        return classNames;
    }

}
